﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;

namespace MT.CustomUserControl.CustomAdorner
{
    /// <summary>
    /// 创建带有拖动矩形的装饰器
    /// </summary>
    public class ThumbBorderAdorner : Adorner
    {
        /// <summary>
        /// 拖拽完成的Action
        /// </summary>
        public Action DragCompletedAction;

        /// <summary>
        /// 装饰器空间的最小Size
        /// </summary>
        private const double elementMinSize = 20;

        /// <summary>
        /// 装饰器矩形的Size
        /// </summary>
        private const double thumbSize = 4;

        /// <summary>
        /// 被装饰的原始控件
        /// </summary>
        private FrameworkElement originalElement = null;

        /// <summary>
        /// 可视元素的集合，来存放装饰控件
        /// </summary>
        private VisualCollection thumbCollec;

        /// <summary>
        /// 返回装饰器的个数
        /// </summary>
        protected override int VisualChildrenCount
        {
            get { return thumbCollec.Count; }   
        }

        /// <summary>
        /// 定义8个可拖动的装饰控件Thumb
        /// </summary>
        private Thumb t_top_left, t_top_center, t_top_right, t_center_left, t_center_right, t_bottom_left, t_bottom_center, t_bottom_right;  //定义8个可拖动的装饰控件Thumb

        public ThumbBorderAdorner(UIElement adornedElement) : base(adornedElement)
        {
            originalElement = adornedElement as FrameworkElement;

            //生成8个装饰控件，并设置器鼠标形状和装饰控件在布局容器上的方向位置
            thumbCollec = new VisualCollection(this);
            thumbCollec.Add(t_top_left =        CreateResizeThumb(Cursors.SizeNWSE, HorizontalAlignment.Left,      VerticalAlignment.Top));
            thumbCollec.Add(t_top_center =      CreateResizeThumb(Cursors.SizeNS,   HorizontalAlignment.Center,    VerticalAlignment.Top));
            thumbCollec.Add(t_top_right =       CreateResizeThumb(Cursors.SizeNESW, HorizontalAlignment.Right,     VerticalAlignment.Top));
            thumbCollec.Add(t_center_left =     CreateResizeThumb(Cursors.SizeWE,   HorizontalAlignment.Left,      VerticalAlignment.Center));
            thumbCollec.Add(t_center_right =    CreateResizeThumb(Cursors.SizeWE,   HorizontalAlignment.Right,     VerticalAlignment.Center));
            thumbCollec.Add(t_bottom_left =     CreateResizeThumb(Cursors.SizeNESW, HorizontalAlignment.Left,      VerticalAlignment.Bottom));
            thumbCollec.Add(t_bottom_center =   CreateResizeThumb(Cursors.SizeNS,   HorizontalAlignment.Center,    VerticalAlignment.Bottom));
            thumbCollec.Add(t_bottom_right =    CreateResizeThumb(Cursors.SizeNWSE, HorizontalAlignment.Right,     VerticalAlignment.Bottom));
        }

        /// <summary>
        /// 创建可变大小的Thumb控件
        /// </summary>
        /// <param name="cursor"></param>
        /// <param name="hor"></param>
        /// <param name="ver"></param>
        /// <returns></returns>
        private Thumb CreateResizeThumb(Cursor cursor, HorizontalAlignment hor, VerticalAlignment ver)
        {
            Thumb thumb = new Thumb()
            {
                Width = thumbSize,
                Height = thumbSize,
                Cursor = cursor,
                HorizontalAlignment = hor,
                VerticalAlignment = ver,

                //设置Thumb控件的模板，即使用正方形
                Template = new ControlTemplate(typeof(Thumb))
                {
                    VisualTree = CreateRectangle(new SolidColorBrush(Colors.Red))
                }

            };

            //主要设置4个边拖动时，在布局容器钟的位置变化
            thumb.DragDelta += (s, e) =>
            {
                var element = originalElement; 
                if (element == null)
                    return; 

                //判断长宽是否合法
                if(Double.IsNaN(element.Width))
                    element.Width = element.RenderSize.Width;

                if (Double.IsNaN(element.Height))
                    element.Height = element.RenderSize.Height;

                switch (thumb.HorizontalAlignment)
                {
                    case HorizontalAlignment.Left:
                        {
                            if (element.Width - e.HorizontalChange > elementMinSize)
                            {
                                double temp = element.Width - e.HorizontalChange;
                                element.Width = temp > 0 ? temp : element.Width;

                                Canvas.SetLeft(element, Canvas.GetLeft(element) + e.HorizontalChange);
                            }
                        }
                        break;
                    case HorizontalAlignment.Right:
                        {
                            if (element.Width - e.HorizontalChange > elementMinSize)
                            {
                                double temp = element.Width + e.HorizontalChange;
                                element.Width = temp > 0 ? temp : element.Width;
                            }
                        }
                        break;
                    default: break;
                }

                switch (thumb.VerticalAlignment) 
                {
                    case VerticalAlignment.Top:
                        {
                            if (element.Height - e.VerticalChange > elementMinSize)
                            {
                                double temp = element.Height - e.VerticalChange;
                                element.Height = temp > 0 ? temp : element.Height;
                                Canvas.SetTop(element, Canvas.GetTop(element) + e.VerticalChange);
                            }
                        }
                        break;
                    case VerticalAlignment.Bottom:
                        {
                            if (element.Height + e.VerticalChange > elementMinSize)
                            {
                                double temp = element.Height + e.VerticalChange;
                                element.Height = temp > 0 ? temp : element.Height;
                            }
                        }
                        break;
                    default: break;
                }
                e.Handled = true;
            };

            thumb.DragCompleted += (s, e) =>
            {
                DragCompletedAction?.Invoke();
            };

            return thumb;
        }

        /// <summary>
        /// 创建Thumb小矩形
        /// </summary>
        /// <param name="solidColorBrush"></param>
        /// <returns></returns>
        private FrameworkElementFactory CreateRectangle(SolidColorBrush solidColorBrush)
        {
            var fef = new FrameworkElementFactory(typeof(Rectangle));
            fef.SetValue(Rectangle.FillProperty, solidColorBrush);
            //fef.SetValue(Rectangle.StrokeProperty, solidColorBrush);
            return fef;
        }

        /// <summary>
        /// Get Visual Child by index
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        protected override Visual GetVisualChild(int index)
        {
            return thumbCollec[index];
        }

        /// <summary>
        /// 在派生类钟重写，为FrameworkElement的派生类定位子元素
        /// 计算所有Thumb控件的位置
        /// </summary>
        /// <param name="finalSize"></param>
        /// <returns></returns>
        protected override Size ArrangeOverride(Size finalSize)
        {            
            Size size = new Size(thumbSize, thumbSize);
         
            double offset = thumbSize / 2;
            t_top_left.Arrange(new Rect(new Point(-offset, -offset), size));
            t_top_center.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width / 2 - offset, -offset), size));
            t_top_right.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width - offset, -offset), size));

            t_center_left.Arrange(new Rect(new Point(-offset, AdornedElement.RenderSize.Height / 2 - offset), size));
            t_center_right.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width - offset, AdornedElement.RenderSize.Height / 2 - offset), size));

            t_bottom_left.Arrange(new Rect(new Point(-offset, AdornedElement.RenderSize.Height - offset), size));
            t_bottom_center.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width / 2 - offset, AdornedElement.RenderSize.Height - offset), size));
            t_bottom_right.Arrange(new Rect(new Point(AdornedElement.RenderSize.Width - offset, AdornedElement.RenderSize.Height - offset), size));

            return finalSize;
        }
    }
}
